﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace FileCopy.Common
{
    public class Command
    {
        private static string _commandPattern = @"^(\w+)\|([^\|]+)\|(.*)$"; // Finds a word followed by a pipe, then at least one character except a pipe, followed by a pipe, then anything.

        /// <summary>
        /// Gets the acknowledgement text for a specific key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="type">The acknowledgement type.</param>
        public static string GetAcknowledgement(string key, CommandType type)
        {
            switch (type)
            {
                case CommandType.NewFile:
                case CommandType.FileContent:
                case CommandType.EndOfFile:
                    return String.Format("{0}Ack", key);

                default:
                    throw new NotImplementedException(String.Format("Support for {0} is not implemented.", type.ToString()));
            }
        }

        /// <summary>
        /// Checks if the data is a valid command.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns><c>True</c> if the data is a command. Otherwise, <c>false</c>.</returns>
        public static bool IsValid(string command)
        {
            return Regex.IsMatch(command, _commandPattern, RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// Builds a command.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="key">The (unique) key</param>
        /// <param name="type">The type.</param>
        /// <returns>The complete command.</returns>
        public static CommandObject Build(string data, string key, CommandType type)
        {
            // Build the command and ensure it is valid.
            string command = String.Format("{0}|{1}|{2}", type.ToString(), key, data);
            if (!IsValid(command))
            {
                throw new Exception("The given values do not make a valid command.");
            }

            return Get(command);
        }

        /// <summary>
        /// Gets the type of a command.
        /// </summary>
        /// <param name="command">The command.</param>
        /// <returns><c>null</c> if the command is not found or is invalid.</returns>
        public static CommandObject Get(string command)
        {
            // Ensure the given value is a valid command.
            if (!IsValid(command))
            {
                throw new ArgumentException("The given value is not a specified command. Check using IsValid() before calling this method.");
            }

            Match match = Regex.Match(command, _commandPattern);
            if (!match.Success)
            {
                throw new Exception("The given value is not a valid command.");
            }

            return new CommandObject
            {
                Type = (CommandType)Enum.Parse(typeof(CommandType), match.Groups[1].Value),
                Key = match.Groups[2].Value,
                Data = match.Groups[3].Value
            };
        }

        /// <summary>
        /// A command sent and received.
        /// </summary>
        public struct CommandObject
        {
            public CommandType Type;
            public string Key;
            public string Data;

            public override string ToString()
            {
                string command = String.Format("{0}|{1}|{2}", Type.ToString(), Key, Data);
                if (!IsValid(command))
                {
                    throw new Exception("Command is not valid.");
                }

                return command;
            }
        }
    }

    public enum CommandType
    {
        NewFile,
        FileContent,
        EndOfFile,
        Resend,
    }
}
